﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using ALDIOrganizer.Properties;

namespace ALDIOrganizer
{
    public class Request : IComparable
    {
        internal DataRow Row;

        public Request(DataRow pRow)
        {
            Row = pRow;
        }

        object _foo;

        public string Whose
        {
            get
            {
                return SQLiteAccess.GetEmployeeFullName(empID);
            }
            set
            {
                _foo = value; // I can't remember exactly, but there were some problems with data binding without it (a bug?)
            }
        }

        public string From
        {
            get
            {
                return startDate.ToShortDateString();
            }
        }

        public string Until
        {
            get
            {
                return endDate.HasValue ?
                    endDate.Value.ToShortDateString() :
                    String.Empty;
            }
        }

        public string HoursDescriptive
        {
            get
            {
                return TimeByQuarters.GetDescriptiveString(
                    ForbiddenAfterHour,
                    ForbiddenBeforeHour);
            }
        }

        public string WeekdaysDescriptive
        {
            get
            {
                if (!AnySpecificWeekdays)
                {
                    return String.Empty;
                }
                if (Days.Length == 1)
                {
                    return Days[0].Plural();
                }

                #region "Mondays, Tuesdays and Thursdays" etc.
                var _without_last_one = new Weekday[Days.Length - 1];
                Array.Copy(
                    Days,
                    _without_last_one,
                    Days.Length - 1);
                string _result = String.Join(
                    ", ",
                    (from _day in _without_last_one
                     select _day.Plural()).ToArray());
                _result += Resources.RequestBindingField_and +
                    Days.Last().Plural();
                return _result;                
                #endregion                
            }
        }

        public string Status
        {
            get
            {
                if (endDate.HasValue)
                {
                    if (endDate.Value < DateTime.Now)
                    {
                        return Resources.RequestStatus_Passed;
                    }
                }
                return Pending ?
                    Resources.STATUS_Pending :
                    Resources.RequestStatus_Active;
            }
        }


        public Int64 ID
        {
            get
            {
                if (Row[0] == null)
                {
                    return -1;
                }
                if (Row[0].GetType() != typeof(Int64))
                {
                    return -1;
                }
                return (Int64)Row[0];
            }
            set
            {
                Row[0] = (Int64)value;
            }
        }

        public Int64 empID
        {
            get
            {
                if (Row[1] == null)
                {
                    return -1;
                }
                if (Row[1].GetType() != typeof(Int64))
                {
                    return -1;
                }
                return (Int64)Row[1];
            }
            set
            {
                Row[1] = (Int64)value;
            }
        }

        public DateTime startDate
        {
            get
            {
                return ((DateTime)Row[2]).Date;
            }
            set
            {
                Row[2] = (DateTime)value.Date;
            }
        }

        public DateTime? endDate
        {
            get
            {
                try
                {
                    return (Row[3] == DBNull.Value) ?
                        (DateTime?)null :
                        (DateTime?)Row[3];
                }
                catch
                {
                    return (DateTime?)null;
                }
            }
            set 
            {
                if (value.HasValue)
                {
                    Row[3] = ((DateTime)value).Date;
                }
                else
                {
                    Row[3] = DBNull.Value;
                }
            }
        }

        public TimeByQuarters? ForbiddenBeforeHour
        {
            get
            {
                if (Row[4] == null ||
                    Row[4] == DBNull.Value)
                {
                    return (TimeByQuarters?)null;
                }
                if (Row[4].GetType() == typeof (Int64) &&
                    (Int64) Row[4] == 0)
                {
                    return (TimeByQuarters?) null;
                }
                return (new TimeByQuarters(Convert.ToByte(Row[4]))) as TimeByQuarters?;
            }
            set            
            {
                if (value.HasValue)
                {
                    Row[4] = ((TimeByQuarters)value).Time;
                }
                else
                {
                    Row[4] = DBNull.Value;
                }
            }
        }

        public TimeByQuarters? ForbiddenAfterHour
        {
            get
            {
                if (Row[5] == null ||
                    Row[5] == DBNull.Value)
                {
                    return (TimeByQuarters?)null;
                }
                if (Row[5].GetType() == typeof (Int64) &&
                    (Int64) Row[5] == 0)
                {
                    return (TimeByQuarters?) null;
                }
                return (new TimeByQuarters(Convert.ToByte(Row[5]))) as TimeByQuarters?;
            }
            set
            {
                if (value.HasValue)
                {
                    Row[5] = ((TimeByQuarters)value).Time;
                }
                else
                {
                    Row[5] = DBNull.Value;
                }
            }
        }

        public Weekday[] Days
        {
            get
            {
                return Row[6] == null ?
                    new Weekday[] {} :
                    ParseToWeekdays((Int64)Row[6]);
            }
            set
            {
                if (value != null)
                {
                    Row[6] = value.ToFlagInt();
                }
                else
                {
                    Row[6] = 0;
                }
            }
        }

        public bool AnySpecificWeekdays
        {
            get
            {
                return (Days.Length > 0);
            }
        }

        public bool AnySpecificHours
        {
            get
            {
                return (ForbiddenBeforeHour.HasValue ||
                    ForbiddenAfterHour.HasValue);
            }
        }

        public bool Pending
        {
            get
            {
                if (Row[7] == null)
                {
                    return false;
                }
                if (Row[7].GetType() != typeof(bool))
                {
                    return false;
                }
                return (bool)Row[7];
            }
            set
            {
                Row[7] = (bool)value ? 1 : 0;
            }
        }


        public string Comments
        {
            get
            {
                return (Row[8] is string) ?
                    (string)Row[8] :
                    String.Empty;
            }
            set
            {
                if (value is string)
                {
                    Row[8] = (string)value;
                }
                else
                {
                    Row[8] = DBNull.Value;
                }
            }
        }

        public override string ToString()
        {
            if (AnySpecificHours)
            {
                return String.Concat(
                    Resources.Request_Not,
                    HoursDescriptive);
            }
            return Resources.Request_DayOff;                            
        }
        

        

        public bool CollidesWith(
            Shift pShift,
            bool pCheckDateFrames)
        {
            
            if (!AppliesOnDay(
                pShift.When,
                pCheckDateFrames))
            {
                return false;
            }

            if (ForbiddenBeforeHour.HasValue &&
                !(ForbiddenBeforeHour.Value > pShift.Start))
            {                
                return false; // 
            }
            return !ForbiddenAfterHour.HasValue || (ForbiddenAfterHour.Value < pShift.Finish);
        }

        public bool AppliesOnDay(
            DateTime pWhatDay,
            bool pCheckDateFrames)
        {
            if (Pending)
            {
                return false;
            }
            if (pCheckDateFrames)
            {
                if (startDate > pWhatDay)
                {
                    return false;
                }
                if (endDate.HasValue)
                {
                    if (endDate.Value < pWhatDay)
                    {
                        return false;
                    }
                }
            }
            if (AnySpecificWeekdays)
            {
                var _whatDayPassed = Time.ToWeekday(pWhatDay.DayOfWeek);
                if (!Days.Contains(_whatDayPassed))
                {
                    return false;
                }
            }
            return true;
        }

        internal static Weekday[] ParseToWeekdays(long pInt)
        {
            var _list = new List<Weekday>();
            foreach (var _day in Time.AllWeekdays)
            {
                if ((pInt & _day.AsFlag()) != 0)
                    _list.Add(_day);
            }
            return _list.ToArray();
        }

        
        #region IComparable Members

        public int CompareTo(object obj)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
